/*
 * Copyright (C) 2008 Universidade Federal de Campina Grande
 *  
 * This file is part of OurGrid. 
 *
 * OurGrid is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free 
 * Software Foundation, either version 3 of the License, or (at your option) 
 * any later version. 
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details. 
 * 
 * You should have received a copy of the GNU Lesser General Public License 
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package org.ourgrid.discoveryservice.controller;

import static org.ourgrid.common.interfaces.Constants.LINE_SEPARATOR;

import java.util.List;

import org.ourgrid.common.config.Configuration;
import org.ourgrid.common.interfaces.DiscoveryService;
import org.ourgrid.common.interfaces.management.DiscoveryServiceManager;
import org.ourgrid.common.interfaces.status.DiscoveryServiceStatusProviderClient;
import org.ourgrid.common.statistics.util.hibernate.HibernateUtil;
import org.ourgrid.discoveryservice.DiscoveryServiceConstants;
import org.ourgrid.discoveryservice.PeerStatusChangeUtil;
import org.ourgrid.discoveryservice.config.DiscoveryServiceConfiguration;
import org.ourgrid.discoveryservice.controller.messages.DiscoveryServiceControlMessages;
import org.ourgrid.discoveryservice.dao.DiscoveryServiceDAO;
import org.ourgrid.discoveryservice.status.DiscoveryServiceCompleteStatus;

import br.edu.ufcg.lsd.commune.Application;
import br.edu.ufcg.lsd.commune.ApplicationProperties;
import br.edu.ufcg.lsd.commune.api.FailureNotification;
import br.edu.ufcg.lsd.commune.api.MonitoredBy;
import br.edu.ufcg.lsd.commune.api.RecoveryNotification;
import br.edu.ufcg.lsd.commune.container.ContainerContext;
import br.edu.ufcg.lsd.commune.container.control.ApplicationControlClient;
import br.edu.ufcg.lsd.commune.container.control.ApplicationServerController;
import br.edu.ufcg.lsd.commune.container.logging.CommuneLogger;
import br.edu.ufcg.lsd.commune.identification.ServiceID;

public class DiscoveryServiceComponentController extends ApplicationServerController 
	implements DiscoveryServiceManager {

	private static final String CONF_XML_PATH = "ds-hibernate.cfg.xml";
	
	/* (non-Javadoc)
	 * @see br.edu.ufcg.lsd.commune.container.control.ApplicationServerController#getComponentName()
	 */
	@Override
	public String getComponentName() {
		return "DiscoveryService";
	}

	/* (non-Javadoc)
	 * @see br.edu.ufcg.lsd.commune.container.control.ApplicationServerController#createDAOs()
	 */
	@Override
	protected void createDAOs() {
		getServiceManager().createDAO(DiscoveryServiceDAO.class);
	}
	
	/* (non-Javadoc)
	 * @see br.edu.ufcg.lsd.commune.container.control.ApplicationServerController#createServices()
	 */
	@Override
	protected void createServices() {
		getServiceManager().deploy(DiscoveryServiceConstants.DS_MONITOR, new DiscoveryServiceNotificationController());
		getServiceManager().deploy(DiscoveryServiceConstants.DS_OBJECT_NAME, new DiscoveryServiceController());
		getServiceManager().deploy(DiscoveryServiceConstants.COMMUNITY_STATUS_PROVIDER, new CommunityStatusProviderController());
	}
	
	/* (non-Javadoc)
	 * @see br.edu.ufcg.lsd.commune.container.control.ApplicationServerController#startComponent()
	 */
	@Override
	protected void startComponent() throws Exception {
		
		HibernateUtil.setUp(CONF_XML_PATH);
		
		CommuneLogger logger = getServiceManager().getLog();
		logger.info(DiscoveryServiceControlMessages.getSuccessfullyStartedDiscoveryServiceMessage());
		
		killAllActivePeers();
		
		registerInterestOnNetwork();
	}

	private void registerInterestOnNetwork() {
		List<ServiceID> networkSids = DiscoveryServiceConfiguration.parseNetwork(getServiceManager());
		
		for (ServiceID dsAdress: networkSids) {
			getServiceManager().registerInterest(DiscoveryServiceConstants.DS_MONITOR, 
					dsAdress.toString(), DiscoveryService.class);
		}
		
	}

	private void killAllActivePeers() {
		PeerStatusChangeUtil.killAllActivePeers(System.currentTimeMillis());
	}

	public void getCompleteStatus(@MonitoredBy(Application.CONTROL_OBJECT_NAME) 
			DiscoveryServiceStatusProviderClient client) {
		if (canStatusBeUsed()) {
			DiscoveryServiceCompleteStatus completeStatus = getCompleteStatus();
			client.hereIsCompleteStatus( completeStatus );
		}
	}
	
	private DiscoveryServiceCompleteStatus getCompleteStatus() {
		return new DiscoveryServiceCompleteStatus( 
				getServiceManager().getDAO(DiscoveryServiceDAO.class).getOnlinePeers(),
				getServiceManager().getContainerDAO().getUpTime(),
				getDescription(getServiceManager().getContainerContext()) );
	}

	@RecoveryNotification
	public void controlClientIsUp(
			DiscoveryServiceStatusProviderClient statusProviderClient) { }
	
	@FailureNotification
	public void controlClientIsDown(
			DiscoveryServiceStatusProviderClient statusProviderClient) { }
	
	private String getDescription(ContainerContext containerContext) {
		
		StringBuilder conf = new StringBuilder();

		conf.append( "\tVersion: " ).append( Configuration.VERSION ).append( LINE_SEPARATOR );

		conf.append( "\tConfiguration directory: " );
		conf.append( containerContext.getProperty(ApplicationProperties.PROP_CONFDIR) );
		conf.append( LINE_SEPARATOR );
		
		conf.append( containerContext.toString() );

		return conf.toString();
	}

	@Override
	protected boolean validateStartSenderPublicKey(ApplicationControlClient client, String senderPublicKey) {
		
		if(!getServiceManager().isThisMyPublicKey(senderPublicKey)) {
			getServiceManager().getLog().warn(DiscoveryServiceControlMessages.getUnknownSenderStartingDiscoveryServiceMessage(senderPublicKey));
			return false;
		}
		return true;
	}
	
	@Override
	protected boolean validateStopSenderPublicKey(ApplicationControlClient client, String senderPublicKey) {
		
		if(!getServiceManager().isThisMyPublicKey(senderPublicKey)) {
			getServiceManager().getLog().warn(DiscoveryServiceControlMessages.getUnknownSenderStoppingDiscoveryServiceMessage(senderPublicKey));
			return false;
		}
		return true;
	}
}
